﻿using System.Collections.Generic;
using System.Windows.Media.Media3D;

namespace Wen.UI.NavigationElements
{
	internal class CameraRotationViewModel : CameraXyzControlViewModelBase
	{
		private const double RotationStep = 1;

		private readonly List<AxisAngleRotation3D> _appliedTransforms = new List<AxisAngleRotation3D>();

		public CameraRotationViewModel(ProjectionCamera camera)
			: base(camera) {
		}

		protected override void ApplyXMovement(double step) {
			ApplyRotation(new Vector3D(1, 0, 0), step);
		}

		protected override void ApplyYMovement(double step) {
			ApplyRotation(new Vector3D(0, 1, 0), step);
		}

		protected override void ApplyZMovement(double step) {
			ApplyRotation(new Vector3D(0, 0, 1), step);
		}

		protected override void Reset() {
			_appliedTransforms.Reverse();
			foreach (AxisAngleRotation3D axisAngleRotation3D in _appliedTransforms) {
				ApplyRotation(new Vector3D(axisAngleRotation3D.Axis.X, axisAngleRotation3D.Axis.Y, axisAngleRotation3D.Axis.Z), -axisAngleRotation3D.Angle, false);
			}
			_appliedTransforms.Clear();
		}

		protected override Point3D RawCoords {
			get {
				double x = 0;
				double y = 0;
				double z = 0;
				foreach (AxisAngleRotation3D axisAngleRotation3D in _appliedTransforms) {
					if (axisAngleRotation3D.Axis.X > 0)
						x += axisAngleRotation3D.Angle;
					if (axisAngleRotation3D.Axis.Y > 0)
						y += axisAngleRotation3D.Angle;
					if (axisAngleRotation3D.Axis.Z > 0)
						z += axisAngleRotation3D.Angle;
				}
				return new Point3D(x, y, z);
			}
		}

		private void ApplyTransform(Transform3D transform3D) {
			if (Camera.Transform is Transform3DGroup)
				((Transform3DGroup) Camera.Transform).Children.Add(transform3D);
			else
				((MatrixTransform3D)Camera.Transform).Matrix *= transform3D.Value;
		}

		private void ApplyRotation(Vector3D vector3D, double angle, bool logRotation = true) {
			AxisAngleRotation3D axisAngleRotation3D = new AxisAngleRotation3D(vector3D, angle);
			ApplyTransform(new RotateTransform3D() { Rotation = axisAngleRotation3D });
			if (logRotation)
				_appliedTransforms.Add(axisAngleRotation3D);
		}

		protected override double Step {
			get {
				return RotationStep;
			}
		}
	}
}
